package org.phalanx.client.mapeditor;

import java.awt.Color;
import java.awt.Container;
import java.awt.Cursor;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.ArrayList;

import javax.swing.BoxLayout;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;

import org.phalanx.client.PhalanxClient;
import org.phalanx.client.UI.DialogManager;
import org.phalanx.client.UI.MouseCursorFactory;
import org.phalanx.client.UI.PhalanxPanelManager;
import org.phalanx.client.dialogs.MainMenuPanel;
import org.phalanx.client.dialogs.PhalanxWindow;
import org.phalanx.client.mapeditor.dialogs.DefaultTileSetDialog;
import org.phalanx.client.mapeditor.dialogs.PhalanxMapInfoDialog;
import org.phalanx.client.mapeditor.dialogs.PhalanxMapTileSetChooserDialog;
import org.phalanx.client.mapeditor.dialogs.PhalanxNewMapDialog;
import org.phalanx.client.mapeditor.editortools.MapSelectionMatrix;
import org.phalanx.map.MapCoordinates;
import org.phalanx.map.MapTile;
import org.phalanx.map.MapTileSet;
import org.phalanx.map.PhalanxMap;

public class PhalanxMapEditorPanel extends JPanel implements MouseListener,
		MouseMotionListener {
	private PhalanxEditorTopToolBarPanel toolBar;
	private PhalanxEditorSideBarPanel sideBar;
	private PhalanxEditorDisplayViewPanel displayContainer;
	private PhalanxWindow masterFrame;
	private PhalanxMapEditorStatusBar statusBar;
	private PhalanxEditorSideToolBarPanel sideToolBar;
	private PhalanxMapTileSetViewer tileSetView;
	private String actionMode;
	private MapSelectionMatrix mouseDraggedMatrix;
	private String currentDirectory;
	public static final String NAME = "MapEditor";

	public static final String SELECTION_MODE = "SELECTION";
	public static final String ADDTILE_MODE = "ADDTILE";
	public static final String REMOVE_MODE = "REMOVE";
	public static final String BUILD_POINT_ADD_MODE = "BUILDPOINTADD";
	public static final String BUILD_POINT_DEL_MODE = "BUILDPOINTDEL";
	public static final String ZOOM_IN_MODE = "ZOOMIN";
	public static final String ZOOM_OUT_MODE = "ZOOMOUT";
	public static final String NAV_MODE = "NAVOUT";
	
	public PhalanxMapEditorPanel(PhalanxWindow masterFrame) {
		this.masterFrame = masterFrame;
	}

	public void initializePanel() {
		this.setBackground(Color.black);
		this.setLayout(new GridBagLayout());
		createTopToolBarPanel();
		createSideBarPanel();
		createDisplayPanel();
		// createSideToolBarPanel();
		createStatusBarPanel();
		currentDirectory = System.getProperty("user.dir");

		sideToolBar.getToolbarAction().setActionModeSelected();
		tileSetView.setCurrentMapTileSet(PhalanxClient.getClientInstance()
				.getDefaultTileSet());
	}

	public void setActionMode(String action) {
		actionMode = action;
		statusBar.setInformationStatus(action);

		if (action.equals(SELECTION_MODE)) {
			this.getDisplayContainer().getMapViewObject().setCursor(
					new Cursor(Cursor.DEFAULT_CURSOR));
		} 
		else if (action.equals(ADDTILE_MODE)) {
			// Cursor writeCursor = new Cursor();
			this.getDisplayContainer().getMapViewObject().setCursor(
					MouseCursorFactory.getWriteTileCursor());
		}
		else if (action.equals(BUILD_POINT_ADD_MODE)){
			this.getDisplayContainer().getMapViewObject().setCursor(
					new Cursor(Cursor.DEFAULT_CURSOR));
		}
		else if (action.equals(BUILD_POINT_DEL_MODE)){
			this.getDisplayContainer().getMapViewObject().setCursor(
					new Cursor(Cursor.DEFAULT_CURSOR));
		}
		else if (action.equals(REMOVE_MODE)){
			this.getDisplayContainer().getMapViewObject().setCursor(
					new Cursor(Cursor.DEFAULT_CURSOR));
		}
		else if (action.equals(ZOOM_IN_MODE)) {
			this.getDisplayContainer().getMapViewObject().setCursor(
					MouseCursorFactory.getZoomInCursor());
		}
		else if (action.equals(ZOOM_OUT_MODE)) {
			this.getDisplayContainer().getMapViewObject().setCursor(
					MouseCursorFactory.getZoomOutCursor());
		}
		else if (action.equals(NAV_MODE)) {
			this.getDisplayContainer().getMapViewObject().setCursor(
					new Cursor(Cursor.CROSSHAIR_CURSOR));
		}
	}
	
	public void setCurrentDirectory(String wd){
		currentDirectory = wd;
	}
	
	public String getCurrentDirectory(){
		return currentDirectory;
	}

	public void setTileSetView(MapTileSet newTileSet) {
		tileSetView.setCurrentMapTileSet(newTileSet);
	}

	private void createTopToolBarPanel() {
		GridBagConstraints c = new GridBagConstraints();
		c.gridx = 0;
		c.gridy = 0;
		c.gridwidth = 2;
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0.5;

		toolBar = new PhalanxEditorTopToolBarPanel(this);

		this.add(toolBar, c);
	}

	private void createDisplayPanel() {
		GridBagConstraints c = new GridBagConstraints();
		c.gridx = 0;
		c.gridy = 1;
		c.gridwidth = 1;
		c.fill = GridBagConstraints.BOTH;
		c.weightx = 0.75;
		c.weighty = 0.5;

		mouseDraggedMatrix = new MapSelectionMatrix();
		this.displayContainer = new PhalanxEditorDisplayViewPanel(this);
		displayContainer.getMapViewObject().addMouseMotionListener(this);
		displayContainer.getMapViewObject().addMouseListener(this);
		Container cont = new Container();
		cont.setLayout(new BoxLayout(cont, BoxLayout.X_AXIS));
		cont.add(displayContainer);
		this.add(cont, c);
	}
	
	public void rehashTileSetViewer() {
		this.tileSetView.setCurrentMapTileSet(this.getDisplayContainer().getMapViewObject().getMap().getMapTileSet());
	}

	private void createSideBarPanel() {
		GridBagConstraints c = new GridBagConstraints();
		c.gridx = 1;
		c.gridy = 1;
		c.fill = GridBagConstraints.BOTH;
		c.weighty = 0.5;
		c.weightx = .2;

		JPanel containerPanel = new JPanel();
		containerPanel.setLayout(new GridLayout(0, 1));

		sideBar = new PhalanxEditorSideBarPanel(this);
		sideToolBar = new PhalanxEditorSideToolBarPanel(this);
		sideToolBar.applyButtonAction(sideToolBar.getButton("selection"));
		tileSetView = new PhalanxMapTileSetViewer(this);

		containerPanel.add(sideBar);
		containerPanel.add(sideToolBar);
		containerPanel.add(tileSetView);

		this.add(containerPanel, c);
	}

	private void createStatusBarPanel() {
		GridBagConstraints c = new GridBagConstraints();
		c.gridx = 0;
		c.gridy = 2;
		c.fill = GridBagConstraints.HORIZONTAL;
		c.weightx = 0;

		statusBar = new PhalanxMapEditorStatusBar();

		this.add(statusBar, c);
	}

	public PhalanxWindow getMasterFrame() {
		return masterFrame;
	}

	public void setMasterFrame(PhalanxWindow masterFrame) {
		this.masterFrame = masterFrame;
	}

	public PhalanxEditorDisplayViewPanel getDisplayContainer() {
		return this.displayContainer;
	}

	public void mouseDragged(MouseEvent e) {
	}

	public void mouseMoved(MouseEvent e) {
		if (e.getSource().equals(displayContainer.getMapViewObject())) {
			Integer xPos = e.getX();
			Integer yPos = e.getY();
			PhalanxMapEditorView display = this.displayContainer
					.getMapViewObject();
			MapCoordinates c = new MapCoordinates(0, 0);

			c = display.getMapTilePosition(xPos, yPos);

			this.statusBar.setCoordinateTracker(c.getX(), c.getY());
		}
	}

	public void mouseClicked(MouseEvent e) {
		if (e.getSource().equals(displayContainer.getMapViewObject())) {
			if (e.getButton() == MouseEvent.BUTTON1) {
				MapCoordinates c = displayContainer.getMapViewObject()
						.getMapTilePosition(e.getX(), e.getY());
				if (actionMode.equals(SELECTION_MODE)) {
					if (e.getClickCount() == 2) {
						centerMapAtPoints(c);
					}
				}

				else if (actionMode.equals(REMOVE_MODE)) {
					removeTileAtPoints(c);
				}
				
				else if (actionMode.equals(BUILD_POINT_ADD_MODE)){
					addBuildPoint(c);
				}
				
				else if (actionMode.equals(BUILD_POINT_DEL_MODE)){
					deleteBuildPoint(c);
				}
				else if (actionMode.equals(ZOOM_IN_MODE)) {
					zoomMap(true, c);
				}
				else if (actionMode.equals(ZOOM_OUT_MODE)) {
					zoomMap(false, c);
				}
				else if (actionMode.equals(NAV_MODE)) {
					centerMapAtPoints(c);
				}
			}
		}

	}
	
	public void zoomMap(boolean zoomIn, MapCoordinates c) {
		PhalanxMapEditorView currentView = this.getDisplayContainer().getMapViewObject();
		
		Double newZoomLevel = currentView.getZoomLevel() + (zoomIn ? .5 : -.5);
		currentView.setZoomLevel(newZoomLevel);
		
		if (newZoomLevel == currentView.getZoomLevel()) {
			centerMapAtPoints(c);
		}
	}
	
	public void addBuildPoint(MapCoordinates c){
		PhalanxMap currentMap = this.getDisplayContainer().getMapViewObject()
		.getMap();
		
		currentMap.addBuildPoint(c);
		this.getDisplayContainer().getMapViewObject().repaint();
	}
	
	public void deleteBuildPoint(MapCoordinates c){
		PhalanxMap currentMap = this.getDisplayContainer().getMapViewObject()
		.getMap();
		
		currentMap.removeBuildPoint(c);
		this.getDisplayContainer().getMapViewObject().repaint();
	}

	public void removeTileAtPoints(MapCoordinates c) {
		PhalanxMap currentMap = this.getDisplayContainer().getMapViewObject()
				.getMap();
		if (currentMap.getDefaultTile() != null) {
			currentMap.setMapTile(c, currentMap.getDefaultTile());
			this.getDisplayContainer().getMapViewObject().repaint();
		}
	}

	public void writeTileAtPoints(MapCoordinates c) {
		MapTile selTile = tileSetView.getSelectedMapTile();

		if (selTile != null) {
			this.getDisplayContainer().getMapViewObject().getMap().setMapTile(
					c, selTile);
			this.getDisplayContainer().getMapViewObject().repaint();
		}
	}

	public void writeTilesAtMatrix(MapSelectionMatrix m) {
		MapTile selTile = tileSetView.getSelectedMapTile();

		if (selTile != null) {
			ArrayList<MapCoordinates> coordinatesArray = m
					.getSelectionMatrixArray();

			for (int i = 0; i < coordinatesArray.size(); i++) {
				MapCoordinates c = coordinatesArray.get(i);
				this.getDisplayContainer().getMapViewObject().getMap()
						.setMapTile(c, selTile);
			}
			this.getDisplayContainer().getMapViewObject().repaint();
		}
	}

	public void selectSingleTileAtPoints(MapCoordinates c) {
		displayContainer.getMapViewObject().setSelectionArea(
				new MapSelectionMatrix(c, c));
		displayContainer.getMapViewObject().repaint();
		sideBar.getInfoPanel().invokeData();
	}

	public void selectTileAtMatrix(MapSelectionMatrix m) {
		displayContainer.getMapViewObject().setSelectionArea(m);
		displayContainer.getMapViewObject().repaint();
		sideBar.getInfoPanel().invokeData();
	}

	public void centerMapAtPoints(MapCoordinates c) {
		displayContainer.getMapViewObject().setCoordinates(c.getX(), c.getY());
		displayContainer.getMapViewObject().repaint();
	}

	public void mouseEntered(MouseEvent e) {
		// TODO Auto-generated method stub

	}

	public void mouseExited(MouseEvent e) {
		// TODO Auto-generated method stub

	}

	public void mousePressed(MouseEvent e) {
		MapCoordinates coords = displayContainer.getMapViewObject()
				.getMapTilePosition(e.getX(), e.getY());

		if (e.getButton() == MouseEvent.BUTTON1) {
			mouseDraggedMatrix.setSelectionMatrixPoints(coords, coords);
		}
	}

	public void mouseReleased(MouseEvent e) {
		if (e.getButton() == MouseEvent.BUTTON1) {
			MapCoordinates coords = displayContainer.getMapViewObject()
					.getMapTilePosition(e.getX(), e.getY());
			mouseDraggedMatrix.setSelectionMatrixPoints(mouseDraggedMatrix
					.getSelectionMatrixStart(), coords);

			if (actionMode.equals(SELECTION_MODE)) {
				selectTileAtMatrix(mouseDraggedMatrix);
			} else if (actionMode.equals(ADDTILE_MODE)) {
				writeTilesAtMatrix(mouseDraggedMatrix);
			}
		}

		mouseDraggedMatrix = new MapSelectionMatrix();
	}
	
	public void createNewMap(PhalanxMap newMap) {
		if (newMap != null) {
			this.getDisplayContainer().getMapViewObject().setMap(newMap);
			this.getDisplayContainer().getMapViewObject().repaint();
			this.getDisplayContainer().setTitle("Untitled");
		}
	}
	
	public void cleanUp() {
		DialogManager d = DialogManager.getInstance();
		
		if (d.getDialog(PhalanxNewMapDialog.NAME) != null) {
			d.getDialog(PhalanxNewMapDialog.NAME).dispose();
			d.removeDialog(PhalanxNewMapDialog.NAME);
		}
		if (d.getDialog(DefaultTileSetDialog.NAME) != null) {
			d.getDialog(DefaultTileSetDialog.NAME).dispose();
			d.removeDialog(DefaultTileSetDialog.NAME);
		}
		if (d.getDialog(PhalanxMapInfoDialog.NAME) != null) {
			d.getDialog(PhalanxMapInfoDialog.NAME).dispose();
			d.removeDialog(PhalanxMapInfoDialog.NAME);
		}
		if (d.getDialog(PhalanxMapTileSetChooserDialog.NAME) != null) {
			d.getDialog(PhalanxMapTileSetChooserDialog.NAME).dispose();
			d.removeDialog(PhalanxMapTileSetChooserDialog.NAME);
		}
	}
	
	public void switchToMainMenu(boolean killEditor) {
		if (killEditor) {
			PhalanxPanelManager.getInstance().removePanel(NAME);
		}
		this.masterFrame.replacePanel(PhalanxPanelManager.getInstance().getPanel(MainMenuPanel.NAME));
	}
}
